package dao

import (
	"context"
	"fmt"
	"time"

	"wxpay/internal/model"
	"wxpay/pkg/util"

	mchApi "wxpay/pkg/wechat_api"
	"github.com/nsqio/go-nsq"
	"github.com/patrickmn/go-cache"
	"gorm.io/gorm"
)

type MchConfig interface {
	// 根据商户号返回服务商配置
	GetMchConfig(ctx context.Context, mchID string) (*model.Mch, error)
	// 根据商户号获取平台证书列表
	GetPlatformCert(ctx context.Context, mchID string) (model.PlatformCerts, error)
	// 根据商户号获取最新的平台证书
	GetLatestPlatformCert(ctx context.Context, mchID string) (*model.PlatformCert, error)
}

type MchConfigRepo struct {
	*gorm.DB
	producer *nsq.Producer
	cache    *cache.Cache
}

func NewMchConfigRepo(d *gorm.DB, p *nsq.Producer, c *cache.Cache) *MchConfigRepo {
	return &MchConfigRepo{
		DB:       d,
		producer: p,
		cache:    c,
	}
}

func (r *MchConfigRepo) GetMchConfig(ctx context.Context, mchID string) (*model.Mch, error) {
	//const op merrors.Op = "dao.GetMchConfig"
	db := r.DB.WithContext(ctx)
	resp := model.Mch{}
	if err := db.Model(&model.Mch{}).Where("mch_id = ?", mchID).First(&resp).Error; err != nil {
		return nil, err
	}
	return &resp, nil
}

const WxUrlHost = "https://api.mch.weixin.qq.com"

func (r *MchConfigRepo) GetPlatformCert(ctx context.Context, mchID string) (model.PlatformCerts, error) {
	cacheKey := fmt.Sprintf("platform-cert-%s", mchID)
	if certs, found := r.cache.Get(cacheKey); found {
		rCerts := certs.(model.PlatformCerts)
		return rCerts, nil
	}
	// 刷新cache
	mch, err := r.GetMchConfig(ctx, mchID)
	if err != nil {
		return nil, err
	}
	client := mchApi.NewBaseClient(mchID, mch.SerialNo, mch.APICert, WxUrlHost, 20*time.Second, mch.APISecret)
	certs, err := client.GetCertificates()
	if err != nil {
		return nil, err
	}
	pCerts := make(model.PlatformCerts, len(certs.Data))
	for i, cert := range certs.Data {
		effectiveTime, err := util.ParseTime(util.LayoutSecondWithTimeZoneAndT, cert.EffectiveTime)
		if err != nil {
			return nil, err
		}
		expireTime, err := util.ParseTime(util.LayoutSecondWithTimeZoneAndT, cert.ExpireTime)
		if err != nil {
			return nil, err
		}
		pCerts[i] = model.PlatformCert{
			SerialNo:      cert.SerialNo,
			EffectiveTime: effectiveTime,
			ExpireTime:    expireTime,
			CertContent:   cert.CertContent,
		}
	}
	r.cache.Set(cacheKey, pCerts, 10*time.Hour)
	return pCerts, nil
}

// 从缓存获取最新的平台证书
func (r *MchConfigRepo) GetLatestPlatformCert(ctx context.Context, mchID string) (*model.PlatformCert, error) {
	certs, err := r.GetPlatformCert(ctx, mchID)
	if err != nil {
		return nil, err
	}
	return certs.GetLatestCert(), nil
}
